﻿using AutoMapper;
using Enter.Admin.Dtoes;
using Enter.Admin.Entities;
using Enter.Admin.Enums;
using Enter.Admin.Filters;
using Enter.Admin.Models;
using Enter.Admin.Models.DataTables;
using Enter.Admin.Utils;
using FreeSql;
using FreeSql.Internal.Model;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

namespace Enter.Admin.Controllers
{
    [TypeFilter(typeof(ActionFilter))]
    public class CaseController : BaseController
    {
        private readonly Upload _upload;
        private readonly Mail _mail;
        private readonly IConfiguration _configuration;

        public CaseController(ILogger<CaseController> logger, IFreeSql fsql, IMapper mapper, Upload upload, Mail mail, IConfiguration configuration) : base(logger, fsql, mapper)
        {
            _upload = upload;
            _mail = mail;
            _configuration = configuration;
        }

        public IActionResult Index1()
        {
            var model = new CaseIndexModel
            {
                CaseType = EnumArchiveCaseType.新一贷,
                Title = "（含批次序号）新一贷（移交特管）",
                Columns = DataTablesColumnExt.ToList<CaseIndex1Model>(),
            };
            return View("Index", model);
        }
        public IActionResult Index2()
        {
            var model = new CaseIndexModel
            {
                CaseType = EnumArchiveCaseType.台账总表,
                Title = "案件台账总表",
                Columns = DataTablesColumnExt.ToList<CaseIndex2Model>(),
            };
            return View("Index", model);
        }
        public IActionResult Index3()
        {
            var model = new CaseIndexModel
            {
                CaseType = EnumArchiveCaseType.贷贷卡台账,
                Title = "贷贷卡台账",
                Columns = DataTablesColumnExt.ToList<CaseIndex3Model>(),
            };
            return View("Index", model);
        }

        [HttpPost]
        public IActionResult Index([FromBody] DataTablesParameters<CaseSearchModel> model)
        {
            // https://docs.microsoft.com/zh-cn/aspnet/core/web-api/jsonpatch?view=aspnetcore-5.0
            var _select = SearchList(model.Data);
            var list = _select.OrderBy(t => t.No).Count(out var total).Skip(model.Start).Take(model.Length).ToList();
            if (model.Data.CaseType == EnumArchiveCaseType.新一贷) 
            {
                var data = _mapper.Map<List<CaseIndex1Model>>(list);
                return Json(new DataTablesResult<CaseIndex1Model>(model.Draw, total, total, data));
            }
            if (model.Data.CaseType == EnumArchiveCaseType.台账总表)
            {
                var data = _mapper.Map<List<CaseIndex2Model>>(list);
                return Json(new DataTablesResult<CaseIndex2Model>(model.Draw, total, total, data));
            }
            if (model.Data.CaseType == EnumArchiveCaseType.贷贷卡台账)
            {
                var data = _mapper.Map<List<CaseIndex3Model>>(list);
                return Json(new DataTablesResult<CaseIndex3Model>(model.Draw, total, total, data));
            }
            return Json(new string[] { });
        }

        private ISelect<Archive> SearchList(CaseSearchModel model)
        {
            var _select = _fsql.Select<Archive>();
            
            _select = _select.WhereIf(model.Id > 0, t => t.Id == model.Id)
             .WhereIf((int)model.CaseType > 0, t => t.CaseType == (int)model.CaseType)
             .WhereIf(!string.IsNullOrWhiteSpace(model.BusinessNo), t => t.BusinessNo == model.BusinessNo)
             .WhereIf(!string.IsNullOrWhiteSpace(model.ContractNo), t => t.ContractNo.Contains(model.ContractNo))
             .WhereIf(!string.IsNullOrWhiteSpace(model.CustomerID), t => t.CustomerID.Contains(model.CustomerID));

            var dynamicWhere = false;
            DynamicFilterInfo info = new DynamicFilterInfo();
            info.Logic = DynamicFilterLogic.And;
            info.Filters = new List<DynamicFilterInfo>();
            foreach (var sm in model.DynamicSearchs) 
            {
                if (!string.IsNullOrWhiteSpace(sm.SearchStringField) && !string.IsNullOrWhiteSpace(sm.SearchStringValue))
                {
                    info.Filters.Add(new DynamicFilterInfo
                    {
                        Field = sm.SearchStringField.Trim(),
                        Value = sm.SearchStringValue,
                        Operator = sm.SearchStringOperator,
                    });
                    dynamicWhere = true;
                }
                if (!string.IsNullOrWhiteSpace(sm.SearchEnumField) && !string.IsNullOrWhiteSpace(sm.SearchEnumValue) && sm.SearchEnumValue != "0")
                {
                    var enum_values = sm.SearchEnumValue.Trim().Split(",");
                    info.Filters.Add(new DynamicFilterInfo
                    {
                        Field = sm.SearchEnumField.Trim(),
                        Value = enum_values, //model.SearchEnumValue,
                        Operator = DynamicFilterOperator.Any,
                    });
                    dynamicWhere = true;
                }
                if (!string.IsNullOrWhiteSpace(sm.SearchDateField) && !string.IsNullOrWhiteSpace(sm.SearchDateValue))
                {
                    info.Filters.Add(new DynamicFilterInfo
                    {
                        Field = sm.SearchDateField.Trim(),
                        Value = sm.SearchDateValue.Split(" - "),
                        Operator = DynamicFilterOperator.DateRange,
                    });
                    dynamicWhere = true;
                }
            }
            
            if (dynamicWhere)
            {
                _select.WhereDynamicFilter(info);
            }
            if (!string.IsNullOrWhiteSpace(model.FullText))
            {
                //DynamicFilterInfo
                _select.Where(t => t.ContractNo.Contains(model.FullText) || t.BatchNo.Contains(model.FullText));
            }
            return _select;
        }

        /// <summary>
        /// 下载
        /// </summary>
        public ActionResult Download(string filename)
        {
            var fileInfo = new FileInfo(filename);
            new FileExtensionContentTypeProvider().Mappings.TryGetValue(Path.GetExtension(filename), out var contenttype);
            return File(fileInfo.OpenRead(), contenttype ?? "application/octet-stream", Path.GetFileName(filename));
        }

        /// <summary>
        /// 下载
        /// </summary>
        public ActionResult Export(long id)
        {
            var att = _fsql.Select<Attachment>(new { Id = id }).First();
            if (att == null || att.IsDeleted)
            {
                return Content("文件不存在.");
            }
            var fileInfo = FileIO.GetFile(att.PathName);
            if (!fileInfo.Exists)
            {
                if (att.IsTemp)
                {
                    return Content("文件不存在.");
                }
                else
                {
                    if (!att.IsSync)
                    {
                        return Content("文件不存在(未同步).");
                    }
                    // 飞临时文件则同步oss;
                    if (_upload.GetObject(att.PathName))
                    {
                        if (!fileInfo.Exists)
                            return Content("文件同步失败.");
                    }
                    else
                    {
                        return Content("文件同步下载失败.");
                    }
                }
            }
            new FileExtensionContentTypeProvider().Mappings.TryGetValue(att.Extension, out var contenttype);
            return File(fileInfo.OpenRead(), contenttype ?? "application/octet-stream", att.Name);
        }

        /// <summary>
        /// 导出查询列表
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        [HttpPost]
        public ActionResult Export([FromBody] CaseExportModel model)
        {
            ISelect<Archive> _select;
            if (model.Rows.Count() > 0)
            {
                _select = _fsql.Select<Archive>().WhereDynamic(model.Rows);
            }
            else
            {
                _select = SearchList(model.Data);
            }
            var name = "档案列表.xlsx";
            var file = FileIO.CreateFile(name, true);
            if (model.Data.CaseType == EnumArchiveCaseType.新一贷)
            {
                var list = _mapper.Map<List<CaseIndex1Model>>(_select.OrderBy(t => t.No).ToList());
                Excel.Save(file.FileInfo, list, model.Columns, EnumsExt.EnumMap, model.ColumnType);
            }
            else if (model.Data.CaseType == EnumArchiveCaseType.台账总表)
            {
                var list = _mapper.Map<List<CaseIndex2Model>>(_select.OrderBy(t => t.No).ToList());
                Excel.Save(file.FileInfo, list, model.Columns, EnumsExt.EnumMap, model.ColumnType);
            }
            else if (model.Data.CaseType == EnumArchiveCaseType.贷贷卡台账)
            {
                var list = _mapper.Map<List<CaseIndex3Model>>(_select.OrderBy(t => t.No).ToList());
                Excel.Save(file.FileInfo, list, model.Columns, EnumsExt.EnumMap, model.ColumnType);
            }
            else 
            {
                return Json(new ResponseResult<string>(false, "参数错误."));
            }
            // 导出;
            //var list = _mapper.Map<List<ArchiveModel>>(_select.OrderByDescending(t => t.Id).ToList());
            //Excel.Save(file.FileInfo, list, model.Columns, EnumsExt.EnumMap);

            // 写入文件;
            var session = Session();
            var db_att = new Attachment
            {
                ObjectType = (int)EnumAttachmentObjectType.临时文件,
                ObjectId = 0,
                IsTemp = true,
                CatalogType = 0,
                Catalog = string.Empty,
                Name = name,
                PathName = file.PathName,
                Extension = file.Extension,
                FileSize = file.FileInfo.Length,
                FileMD5 = FileIO.Md5(file.FileInfo),
                IsSync = false,
                CreateUserId = session.Id,
                CreateTime = DateTime.Now,
                UpdateTime = DateTime.Now,
                IsDeleted = false
            };
            var att_id = _fsql.Insert<Attachment>(db_att).ExecuteIdentity();
            if (att_id > 0)
                return Json(new ResponseResult<long>(true, att_id, "下载成功."));
            return Json(new ResponseResult<string>(false, "下载失败."));
        }

        /// <summary>
        /// 上传导入的文件
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Upload(IEnumerable<IFormFile> files)
        {
            if (files.Count() == 0) return Json(new ResponseResult<string>(false, "请选择文件."));
            var file = files.First();
            if (!file.FileName.EndsWith(".xlsx"))
            {
                return Json(new ResponseResult<string>(false, "不支持的文件类型."));
            }
            var new_file = FileIO.CreateFile(file.FileName, true);
            using (var stream = new_file.FileInfo.Create())
            {
                file.CopyTo(stream);
            }
            return Json(new ResponseResult<string>(true, new_file.FileInfo.FullName, "上传成功."));
        }

        /// <summary>
        /// 导入
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        [HttpPost]
        public ActionResult Import([FromBody] CaseImportModel model)
        {
            if ((int)model.CaseType == 0) 
            {
                return Json(new ResponseResult<string>(false, "参数错误."));
            }
            var insertCount = 0;
            var updateCount = 0;
            var excelCount = 0;

            (List<CaseIndexBaseModel> DataList, List<ExcelAttribute> ExcelColumns, List<string> Errors) excelTuple = ExcelToList(model);            
            //var excelTuple = Excel.ToList<ArchiveModel>(model.FileName, drops: EnumsExt.EnumMap);
            if (excelTuple.Errors.Count > 0)
            {
                var fullName = string.Empty;
                if (excelTuple.Errors.Count > 10)
                {
                    // 错误写入文件;
                    var new_file = FileIO.CreateFile(model.FileName + ".txt", true);
                    using (var fs = new_file.FileInfo.Create())
                    {
                        //实例化一个StreamWriter-->与fs相关联  
                        StreamWriter sw = new StreamWriter(fs);
                        //开始写入
                        foreach (var error_str in excelTuple.Errors)
                        {
                            sw.WriteLine(error_str);
                        }
                        //清空缓冲区  
                        sw.Flush();
                        //关闭流
                        sw.Close();
                        fs.Close();
                    }
                    fullName = new_file.FileInfo.FullName;
                }
                return Json(new ResponseResult<string>(false, fullName, string.Join(" ; ", excelTuple.Errors)));
            }
            if (excelTuple.DataList.Count == 0) 
            {
                return Json(new ResponseResult<string>(false,
                        string.Format("未读取到数据.")
                    ));
            }
            // 判断合同编号是否重复
            var distinct_ContractNo = excelTuple.DataList.Select(t => t.ContractNo).GroupBy(p => p).Where(i => i.Count() > 1);
            if (distinct_ContractNo.Count() > 0)
            {
                if (distinct_ContractNo.Any(t => string.IsNullOrWhiteSpace(t.Key)))
                {
                    return Json(new ResponseResult<string>(false,
                        string.Format("读取到合同编号存在为空的情况(读取行数：{0},请检查是否匹配)", excelTuple.DataList.Count)
                    ));
                }
                return Json(new ResponseResult<string>(false,
                    string.Format("重复合同编号(读取行数：{0})：{1}",
                        excelTuple.DataList.Count,
                        string.Join(",", distinct_ContractNo.Select(t => t.Key))
                    )
                    ));
            }
            var session = Session();
            var repeat_all = new List<string>();
            _fsql.Transaction(() =>
            {
                foreach (var item in excelTuple.DataList)
                {
                    Archive arc = null;

                    if (!string.IsNullOrWhiteSpace(item.ContractNo))
                    {
                        arc = _fsql.Select<Archive>().Where(t=>t.ContractNo == item.ContractNo && t.CaseType == (int)model.CaseType && t.IsDeleted == false).ToOne();
                    }
                    if (arc == null)
                    {
                        // 管理员才能新增。
                        if (session.Role.IsDefault) 
                        {
                            excelCount++;
                            // 查询最大的序号；
                            var max_no = _fsql.Select<Archive>().Where(t => t.CaseType == (int)model.CaseType && t.IsDeleted == false).Max(t => t.No);
                            if (max_no <= 0) max_no = 0;
                             // 新增；
                            arc = new Archive();
                            arc = _mapper.Map<Archive>(item);
                            arc.No = max_no+1;
                            arc.CaseType = (int)model.CaseType;
                            arc.CreateTime = DateTime.Now;
                            arc.UpdateTime = DateTime.Now;
                            arc.IsDeleted = false;
                            // 插入.
                            var ics = excelTuple.ExcelColumns.Select(t => t.PropertyName).ToArray();
                            arc.Id = _fsql.Insert<Archive>(arc)
                                //.InsertColumns(ics)
                                .ExecuteIdentity();
                            insertCount += 1;
                           
                            // 更新通知时间
                            UpdateNoticeDating(arc);
                            
                            // 判断重复项;
                            var repeatCur = Repeat(arc);
                            if (repeatCur.Count > 0)
                            {
                                repeat_all.AddRange(repeatCur);
                            }
                        }
                    }
                    else
                    {
                        // 只能修改自己负责的案件；
                        if (session.Role.IsDefault || arc.ChargeUserId2 == session.Id)
                        {
                            excelCount++;
                            // 主键和序号不更新;
                            item.Id = arc.Id;
                            item.No = arc.No;

                            _mapper.Map(item, arc);
                            var updateColumns = excelTuple.ExcelColumns.Select(t => t.PropertyName).ToList();
                            updateColumns.Add(nameof(arc.UpdateTime));
                            arc.UpdateTime = DateTime.Now;
                            // 空白的列不要更新;
                            var notEmptyColumns = Tools.UpdatedFeils(arc, updateColumns);
                            var u_c = _fsql.Update<Archive>().SetSource(arc).UpdateColumns(notEmptyColumns.ToArray()).ExecuteAffrows();
                            updateCount += u_c;

                            // 更新通知时间
                            UpdateNoticeDating(arc);
                        }
                    }
                }
            });
            var repeat_str = string.Empty;
            repeat_str = string.Join(",", repeat_all.Distinct());
            if (!string.IsNullOrWhiteSpace(repeat_str))
            {
                repeat_str = string.Format(" ({0})", repeat_str);
            }
            return Json(new ResponseResult<string>(true, string.Format("导入成功. (Excel总数：{0}, 修改：{1}, 新增：{2}) {3}", excelCount, updateCount, insertCount, repeat_str)));
        }

        // 更新通知时间;
        private void UpdateNoticeDating(Archive arc)
        {
            var NoticeDatings = _fsql.Select<NoticeDating>().Where(t => t.FromId == arc.Id).ToList();
            // 执行查封、冻结财产到期日
            var allTimes = RegexTools.ExtractDate(arc.ExecutionOutTime);
            foreach (var dt in allTimes)
            {
                addUpdateNoticeDating(NoticeDatings, EnumNoticeDatingNoticeType.Archive_ExecutionOutTime, arc.Id, dt);               
            }
            // SealOutTime 保全到期前45日提前  保全到期日/查封、冻结到期日
            addUpdateNoticeDating(NoticeDatings, EnumNoticeDatingNoticeType.Archive_SealOutTime, arc.Id, arc.SealOutTime);
            // CourtTime   开庭提前10日提醒
            addUpdateNoticeDating(NoticeDatings, EnumNoticeDatingNoticeType.Archive_CourtTime, arc.Id, arc.CourtTime);
            // RenewalTime 委托到期日前45日提醒 委托到期日/续聘到期日
            addUpdateNoticeDating(NoticeDatings, EnumNoticeDatingNoticeType.Archive_RenewalTime, arc.Id, arc.RenewalTime);
        }

        private void addUpdateNoticeDating(List<NoticeDating> NoticeDatings, EnumNoticeDatingNoticeType ntype, long id, DateTime dateTime)
        {
            if (dateTime == DateTime.MinValue) return;
            var exist = NoticeDatings.Where(t => t.NoticeType == (int)ntype & t.Dating == dateTime).Any();
            if (!exist)
            {
                var nd = new NoticeDating { NoticeType = (int)ntype, FromId = id, Dating = dateTime, IsDeleted = false, IsNoticed = false };
                _fsql.Insert<NoticeDating>(nd).ExecuteIdentity();
            }
        }

        // 判断重复项;
        private List<string> Repeat(Archive archive)
        {
            var repeatList = new List<string>();
            {
                var hasRepeat = _fsql.Select<Archive>().Where(t => t.IsDeleted == false && t.CustomerID == archive.CustomerID).Count() > 1;
                if (hasRepeat)
                {
                    repeatList.Add(archive.CustomerID);
                }
            }
            {
                var hasRepeat = _fsql.Select<Archive>().Where(t => t.IsDeleted == false && t.CustomerName == archive.CustomerName).Count() > 1;
                if (hasRepeat)
                {
                    repeatList.Add(archive.CustomerName);
                }
            }
            return repeatList;
        }

        private (List<CaseIndexBaseModel> DataList, List<ExcelAttribute> ExcelColumns, List<string> Errors) ExcelToList(CaseImportModel model)
        {
            if (model.CaseType == EnumArchiveCaseType.新一贷)
            {
                var result = Excel.ToList<CaseIndex1Model>(model.FileName, drops: EnumsExt.EnumMap);
                List<CaseIndexBaseModel> dataList = PraseList<CaseIndexBaseModel>(result.DataList);
                return (dataList, result.ExcelColumns, result.Errors);
            }
            if (model.CaseType == EnumArchiveCaseType.台账总表)
            {
                var result = Excel.ToList<CaseIndex2Model>(model.FileName, drops: EnumsExt.EnumMap);
                List<CaseIndexBaseModel> dataList = PraseList<CaseIndexBaseModel>(result.DataList);
                return (dataList, result.ExcelColumns, result.Errors);
            }
            if (model.CaseType == EnumArchiveCaseType.贷贷卡台账)
            {
                var result = Excel.ToList<CaseIndex3Model>(model.FileName, drops: EnumsExt.EnumMap);
                List<CaseIndexBaseModel> dataList = PraseList<CaseIndexBaseModel>(result.DataList);
                return (dataList, result.ExcelColumns, result.Errors);
            }
            return (new List<CaseIndexBaseModel>(), new List<ExcelAttribute>(), new List<string>());
        }

        private static List<T> PraseList<T>(object listObj)
        {
            List<T> result = new List<T>();
            if (!listObj.GetType().IsGenericType)
                throw new Exception("非集合类型");
            if (listObj as System.Collections.ICollection != null)
            {
                var list = (System.Collections.ICollection)listObj;
                if (list.Count > 0)
                {
                    foreach (var item in list)
                    {
                        result.Add((T)item);
                    }
                }
            }
            return result;
        }

        public ActionResult Detail(long id)
        {
            return View(_fsql.Select<Archive>(new { Id = id }).ToOne());
        }
        public ActionResult Add(int id)
        {
            var session = Session();
            if (!session.Role.IsDefault)
            {
                return Content("没有权限.");
            }
            return View("Edit", new Archive() { CaseType = id });
        }

        // GET: Home/Edit/5
        public ActionResult Edit(long id)
        {
            var session = Session();
            var model = _fsql.Select<Archive>(new { Id = id }).ToOne();
            if (model == null || model.IsDeleted)
            {
                return View("Error", new ErrorViewModel() { StatusCode = 404 });
                // 404
            }
            if (!session.Role.IsDefault && model.ChargeUserId2 != session.Id)
            {
                return Content("没有权限修改.");
            }
            return View(model);
        }

        // POST: Home/Edit/5
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit(long id, Archive model)
        {
            var session = Session();
            if (id == 0)
            {
                if (!session.Role.IsDefault)
                {
                    return Json(new ResponseResult<string>(false, "没有权限."));
                }
                // 查询最大的序号；
                var max_no = _fsql.Select<Archive>().Where(t => t.CaseType == (int)model.CaseType && t.IsDeleted == false).Max(t => t.No);
                if (max_no <= 0) max_no = 0;

                model.No = max_no + 1;
                model.CreateTime = DateTime.Now;
                model.UpdateTime = DateTime.Now;
                model.IsDeleted = false;
                var new_id = _fsql.Insert<Archive>(model).ExecuteIdentity();//.ExecuteAffrows();
                model.Id = new_id;
                if (new_id > 0)
                {
                    // 更新通知时间
                    UpdateNoticeDating(model);
                    // 判断重复项;
                    var repeatCur = Repeat(model);
                    var tips = string.Empty;
                    if (repeatCur.Count > 0)
                    {
                        tips = string.Format("{0}", string.Join(",", repeatCur.Distinct())) ;
                    }
                    return Json(new ResponseResult<string>(true, string.Format("新增成功.{0}", tips)));
                }
                return Json(new ResponseResult<string>(false, "新增失败."));
            }
            else
            {
                model.Id = id;
                var dbModel = _fsql.Select<Archive>(new { Id = id }).ToOne();
                if (!session.Role.IsDefault && dbModel.ChargeUserId2 != session.Id)
                {
                    return Json(new ResponseResult<string>(false, "没有权限修改."));
                }
                if (dbModel.CaseType == (int)EnumArchiveCaseType.台账总表)
                {
                    var update_model = _mapper.Map<CaseIndex2Model>(model);
                    _mapper.Map(update_model, dbModel);
                }
                else if (dbModel.CaseType == (int)EnumArchiveCaseType.贷贷卡台账)
                {
                    var update_model = _mapper.Map<CaseIndex3Model>(model);
                    _mapper.Map(update_model, dbModel);
                }
                else
                {
                    var update_model = _mapper.Map<CaseIndex1Model>(model);
                    _mapper.Map(update_model, dbModel);
                }
                dbModel.UpdateTime = DateTime.Now;
                var count = _fsql.Update<Archive>().SetSource(dbModel).IgnoreColumns(new string[] { "CreateTime" }).ExecuteAffrows();
                if (count > 0)
                {
                    // 更新通知时间
                    UpdateNoticeDating(dbModel);
                    return Json(new ResponseResult<string>(true, "更新成功."));
                }
                return Json(new ResponseResult<string>(false, "更新失败."));
            }
        }

        [HttpPost]
        public ActionResult Delete([FromBody]CaseDeleteModel model)
        {
            var session = Session();
            if (!session.Role.IsDefault)
            {
                return Json(new ResponseResult<string>(false, "没有权限."));
            }
            _fsql.Transaction(() =>
            {
                _fsql.Delete<Archive>().Where(t => model.Ids.Contains(t.Id)).ExecuteAffrows();
            });
            return Json(new ResponseResult<string>(true, "更新成功."));
        }
    }
}
